iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0
自我挑戰組

菜雞也能優雅的征服RxJS系列 第 26

菜雞們一起征服RxJS - day26: 回傳的observable我統一訂閱 - mergeAll

  • 分享至 

  • xImage
  •  

mergeAll


圖片來源 RxJS官網 - mergeAll

  • 先來了解定義的這段話 Flattens an Observable-of-Observables.

換個說法,就是將接下來我會陸續到一堆observable,每接收到一個observable,我就將他扁平化(flatten)

  • /images/emoticon/emoticon04.gif還是很抽象對吧,沒關係,我們用底下這段例子來讓你更清楚。

觀念說明

觀念1: 接收到一般的值

  • 底下這例子我們不難理解,使用者每按下一次滑鼠鍵,就會印出clicked
  • 其中,字串clicked,就是我們接收回來的值,很直覺,對吧!
click$.pipe(
    map(() => 'clicked')
).subscribe(console.log);

觀念2: 接收到的是一個一個observable

  • 我們將上面例子的字串,改為observable,也就是我會接收到一個一個等待訂閱的observable,那該怎麼進行呢?

  • 設計回傳的observable:

使用interval+take讀取3秒
將這些回傳的observable一一的訂閱

來看看範例

// case1: can work but ugly code
let num = 0;
const timer$ = interval(1000).pipe(take(3)); //<-- 建置一個讀取3秒的observable
click$
  .pipe(
    tap(() => {  //<-- 加入tap顯示click的次數
      num += 1;
      console.log('click-', num);
    }),
    map(() => timer$) //<-- 回傳timer$
  )
  .subscribe(
    (obs) => obs.subscribe(console.log) //<-- 接收到observable,訂閱
  );

解析

  • click1: 我只要點選一次,就會獲得一組timer$,在第一層的訂閱接收到後,在裡面的next進行再訂閱,你就會看到timer$就會執行0->1->2
  • click2~4: 接著,我連續點三下,是不是會依序獲得三個observables,依序訂閱後,你就能發現click2~4 對應的timer$就依序被觸發0->1->2
  • click5~6: 依此類推
  • click7~8: 第七次及第八次的點擊,間隔較長,故click7timer$會先進行計數,然後中間click8的點擊發生,故會晚一步計數。

再看一次mergeAll回到彈珠圖,你就懂了☕

mergeAll讓你一次搞定所有的訂閱/images/emoticon/emoticon24.gif

  • 上面的範例,我們必須要在訂閱中再次訂閱接收的observable,看起來可以,但...

如果未來接收的observable還會回傳更多的observable,那豈不是要寫出波動拳程式了。

  • 工程師,寫code就是要帥,mergeAll給他用下去!

case

stackblitz

import { fromEvent, interval } from 'rxjs';
import { map, take, tap, mergeAll } from 'rxjs/operators';

const click$ = fromEvent(document, 'click');
// case2: mergeAll
let num = 0;
const timer$ = interval(1000).pipe(take(3)); //<-- 建置一個讀取3秒的observable
click$
  .pipe(
    tap(() => {
      num += 1;
      console.log('click-', num);
    }),
    map(() => timer$),
    mergeAll() 
  )
  .subscribe(console.log);

沒比較沒傷害/images/emoticon/emoticon39.gif

什麼!還可以更帥 ~ mergeMap/images/emoticon/emoticon30.gif

stackblitz

import { fromEvent, interval } from 'rxjs';
import { mergeMap, map, take, tap, mergeAll } from 'rxjs/operators';

const click$ = fromEvent(document, 'click');
// case2: mergeAll
let num = 0;
const timer$ = interval(1000).pipe(take(3)); //<-- 建置一個讀取3秒的observable
click$
  .pipe(
    tap(() => {
      num += 1;
      console.log('click-', num);
    }),
    // map(() => timer$),
    // mergeAll()

    mergeMap(() => timer$)   //<-- mergeMap: 取代上面兩行
  )
  .subscribe(console.log);
  • mergeMap = map(()=>observable) +mergeAll()

✍Recap

  • 接收回來的可能是observable,要一一的訂閱不是一個好的寫法,這時請服用mergeAll
  • 如果你mergeAll()之前有用map,可以用mergeMap,讓寫法更俐落!

呼~第26天順利達標,距離目標還剩下4天,GOGOGO~~~!!


上一篇
菜雞們一起征服RxJS - day25: 觸發後的時間內我只抓最後一個 auditTime
下一篇
菜雞們一起征服RxJS - day27: 只掌握最新的訂閱: switchAll及switchMap
系列文
菜雞也能優雅的征服RxJS32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言